﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Caching;

using Enyim.Caching;
using Enyim.Caching.Memcached;

using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.CacheService;
using Fuse8.DomainFramework.Common;

namespace Fuse8.DomainFramework.MemcacheProvider
{
    public class MemcacheCacheService<TEntity, TKey> : BaseDependencyCacheService<TEntity, TKey>, IEntityCacheService<TEntity, TKey>, IDisposable 
        where TEntity : class, IEntityObject<TKey>, new()
        where TKey : IComparable<TKey>, IEquatable<TKey> 
    {
        #region Fields

        private MemcachedClient _client;
        private bool _isDisposed = false;

        #endregion

        #region Constructor

        public MemcacheCacheService()
        {
            CacheOptions = new CacheServiceOptions();            
            
            _client = new MemcachedClient();
        }

        public MemcacheCacheService(CacheServiceOptions options)
            : this()
        {
            Guard.ArgumentNotNull(options, "options");

            if (options.AbsoluteTimeSpanExpiration != TimeSpan.Zero)
            {
                CacheOptions.AbsoluteTimeSpanExpiration = options.AbsoluteTimeSpanExpiration;
            }

            CacheOptions.UseAsyncMethods = options.UseAsyncMethods;
        }

        #endregion

        #region IDisposable Members

        ~MemcacheCacheService()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    if (_client != null)
                    {
                        _client.Dispose();
                    }
                }
            }

            _isDisposed = true;
        }

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        #endregion

        #region Override methods

        protected override TStored ClientGet<TStored>(string cacheKey)
        {
            return _client.Get<TStored>(cacheKey);
        }

        protected override IDictionary<string, TStored> ClientGet<TStored>(IEnumerable<string> cacheKey)
        {
            return _client.Get(cacheKey).ToDictionary(p => p.Key, p => (TStored)p.Value);
        }

        protected override bool ClientStore<TStored>(CacheStoreMode mode, string cacheKey, TStored cachedObject, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        {
            bool result = false;

            StoreMode clientStoreMode = StoreMode.Add;

            switch (mode)
            {
                case CacheStoreMode.Add:
                    clientStoreMode = StoreMode.Add;
                    break;
                case CacheStoreMode.Set:
                    clientStoreMode = StoreMode.Set;
                    break;
            }

            if (absoluteExpiration == Cache.NoAbsoluteExpiration)
            {
                result = _client.Store(clientStoreMode, cacheKey, cachedObject);
            }
            else if (slidingExpiration == Cache.NoSlidingExpiration)
            {
                result = _client.Store(clientStoreMode, cacheKey, cachedObject, absoluteExpiration);
            }
            else
            {
                result = _client.Store(clientStoreMode, cacheKey, cachedObject, slidingExpiration);
            }

            return result;
        }

        protected override bool ClientRemove<TStored>(string cacheKey)
        {
            return _client.Remove(cacheKey);
        }

        protected override void ClientFlushAll()
        {
            _client.FlushAll();
        }

        public override IEnumerable<CacheItemView> CacheItems
        {
            get { throw new NotImplementedException(); }
        }
        
        #endregion
    }
}
